var net = require('net');
var util = require('util');
var linereader = require('../linereader/linereader');
var fs = require('fs');

var IrcBot = function () {
    this.debug = false;
    this.ready = false;
    this.onconnect = null;
    this.socket = null;
    this.onmessage = null;
    this.bots = { };
};

IrcBot.prototype.create = function()
{
    return new IrcBot();
}

IrcBot.prototype.connect = function (server, tcpport, nickname)
{
    var thebot = this;
    this.socket = net.connect(
    {
        port: tcpport,
        host: server
    },
    function()
    {
        if (this.debug)
        {
            console.log('Successfully conected to server: ' + server + ":" + tcpport);
        }
        thebot.login(nickname);
    }
    );

    this.socket.setEncoding('utf8');

    var reader = linereader.createReader(function (line)
    {
        thebot.processInput(line);
    });

    this.socket.on('data', function(data)
    {
        reader.append(data);
    });
    this.socket.on('end', function () {
        reader.close();
        if (thebot.debug)
        {
            console.log('Connection to the IRC Server has been terminated.');
        }
    });

    return this;
};

IrcBot.prototype.attach = function (timeout, channel, msgs)
{
    if (isNaN(timeout) || channel.length < 2 || channel[0] != '#' || msgs.length < 1)
    {
        throw "Invalid arguments";
    }
    if (!this.ready)
    {
        throw "Server hasn't connected yet"
    }

    var blob = { msgIndex : 0, messages : msgs, handler : null };
    this.bots[channel] = blob;
    var str = this.strings;
    this.socket.write(util.format(str['join'], channel));
    blob.handler = setInterval(function(bot)
    {
        var blob = bot.bots[channel];
        var msgStr = util.format(str['privmsg'], channel, blob.messages[blob.msgIndex++]);
        bot.socket.write(msgStr, 'utf8', function()
        {
            if (bot.debug)
            {
                console.log(util.format('Successfully sent message of size %s to channel %s', msgStr.length, channel));
            }
        });
        blob.msgIndex %= blob.messages.length;
    }, timeout * 1000, this);
    return blob.handler;
};

IrcBot.prototype.processInput = function(data)
{
    var s = data.toString();
    if (s[0] == ':') // Has owner
    {
        s = s.substr(1);
        var colon = s.indexOf(':');
        var tokens = [];
        if (colon != -1)
        {
            Array.prototype.push.apply(tokens, s.substr(0, colon - 1).split(' '));
            tokens.push(s.substr(colon + 1).trim());
        }
        var code = Number(tokens[1]);
        if (this.debug)
        {
            console.log("Parsed code: " + code);
        }
        if (!isNaN(code))
        {
            this.processServerMessage(Number(tokens[1]), tokens.slice(2));
        }
        else
        {
            if (tokens.length > 0)
            {
                this.processMessage(tokens[0], tokens[1], tokens.slice(2));
            }
        }
        if (this.debug)
        {
            console.log(tokens);
        }
    }
    else // Server command
    {
        tokens = s.split(' ');
        this.processCommand(tokens[0], tokens.slice(1));
    }
};

IrcBot.prototype.processServerMessage = function (code, args) 
{
    smh = this.serverMessageHandlers;
    if (smh[code] != null)
    {
        smh[code](this, args);
    } else if (this.debug)
    {
        console.log("Ignoring code: " + code);
    }
};

IrcBot.prototype.login = function(nickname)
{
    var str = this.strings;
    var thebot = this;
    var userCmd = util.format(str['user'], nickname);
    var nickCmd = util.format(str['nick'], nickname);
    this.socket.write(userCmd, function()
    {
        thebot.socket.write(nickCmd);
    });
},

IrcBot.prototype.processMessage = function(owner, msg, args)
{
    var h = this.messageHandlers[msg.toUpperCase()];
    if (h)
    {
        h(this, owner, args);
    }
};

IrcBot.prototype.processCommand = function(command, args)
{
    var h = this.commandHandlers[command.toUpperCase()];
    if (h)
    {
        h(this, args);
    }
    else if (this.debug)
    {
        console.log("Command: " + command + ":" + args.join(', ') + " is not handled");
    }
};

IrcBot.prototype.disconnect = function()
{
    for (key in this.bots)
    {
        clearInterval(this.bots[key].handler);
    }

    this.socket.write("QUIT :Node.Js IrcBot finishing session...\r\n");
}


IrcBot.prototype.strings = {
    nick: 'NICK %s\r\n',
    user: 'USER %s 8 * :Node.js IRC Bot\r\n',
    privmsg: 'PRIVMSG %s :%s\r\n',
    join: 'JOIN %s\r\n'
};

IrcBot.prototype.commandHandlers = {
    'PING' : function(bot, args)
    {
        if (bot.debug)
            console.log("Received a PING request? PONG!");
        bot.socket.write('PONG ' + args.join(' ') + "\r\n");
    },
    'ERROR' : function(bot, args)
    {
        if (bot.debug)
            console.log("The server has reported an error: " + args.join(''));
    },
};

IrcBot.prototype.messageHandlers = {
    'PRIVMSG' : function(bot, owner, args)
    {
        var dest = args.shift();
        if (bot.onmessage != null)
        {
            bot.onmessage(owner, dest, args);
        }
    },
    'NOTICE' : function(bot, owner, args)
    {
        if (bot.debug)
            console.log(util.format('Notice: ' + args.join(' ')));
    }
};

IrcBot.prototype.serverMessageHandlers = {
    376 : function (bot, args)
    {
        if (bot.debug)
            console.log("IRC negotiation successful.");
        bot.ready = true;
        if (bot.onconnect != null)
        {
            bot.onconnect(bot);
        }
    }
};

module.exports = IrcBot.prototype;

if (process.argv.length > 2)
{
    var args = process.argv.slice(2);
    if (args.length === 4)
    {
        fs.readFile(args[3], function(err, data)
        {
            if (err)
            {
                console.log("Can't read file: " + args[3]);
            }
            else
            {
                var timeout;
                var channel;
                var msgs = new Array();
                var cnt = 0;
                var reader = linereader.createReader(function (line)
                {
                    switch(cnt++)
                    {
                        case 0:
                        var p = line.split(' ');
                        timeout = Number(p[0]);
                        channel = p[1];
                        break;
                        default:
                        msgs.push(line);
                    }
                });
                reader.append(data);
                reader.close();
                console.log("Timeout: " + timeout + "secs, Channel:  " + channel + " msgs: \n" + msgs);
                ibot = new IrcBot();
                ibot.connect(args[0], args[1], args[2]);
                ibot.onconnect = function()
                {
                    ibot.attach(timeout, channel, msgs);
                }
            }
        });
} else
{
    console.error("Invalid arguments, usage ircbot <server> <port> <nickname> <botdatafile>");
}
}
